<?php

namespace Apps\Common\Traits;

use Apps\App\Models\PayAttach;
use Deyi\Alipay\lib\AlipayCore;
use Vendor\WeixinPay\WeixinPay;

Trait PayTrait
{

    //微信支付方式
    public function weixinpay($body, $out_trade_no, $total_fee, $attach)
    {
        $appKey = $this->getDI()->get('config')->weixinpay->appkey;
        $appId = $this->getDI()->get('config')->weixinpay->appid;     //appid
        $partner = $this->getDI()->get('config')->weixinpay->partner;    //财付通商户号
        $notifyUrl = $this->getDI()->get('config')->weixinpay->notifyurl; //通知回调url

        //获取提交的订单号
        $outparams = [];
        $time_stamp = time();
        $nonce_str = md5(mt_rand());

        $attach = PayAttach::getInstance()->addAndReturnId($attach);
        $prepayid = WeixinPay::getPrePayId($appId, $partner, $appKey, md5(mt_rand() . uniqid()), $body, $attach, $out_trade_no, $total_fee, $notifyUrl);

        if ($prepayid) {
            $pack = 'Sign=WXPay';
            $prePaySign = WeixinPay::createAppPayPreSign([
                'appid' => $appId,
                'noncestr' => $nonce_str,
                'package' => $pack,
                'partnerid' => $partner,
                'prepayid' => $prepayid,
                'timestamp' => $time_stamp
            ], $appKey);

            $outparams = [
                'retcode' => 0,
                'retmsg' => 'ok',
                'appid' => $appId,
                'noncestr' => $nonce_str,
                'package' => $pack,
                'prepayid' => $prepayid,
                'timestamp' => $time_stamp,
                'sign' => $prePaySign
            ];

        } else {
            $outparams = [
                'retcode' => -2,
                'retmsg' => '错误：获取prepayId失败',
            ];
        }
        return $outparams;
    }

    //支付宝支付方式
    public function alipay($goodsId, $subject, $out_trade_no, $total_fee, $body)
    {

        $partner = $this->getDI()->get('config')->alipay->partner; //合作身份者id
        $inputCharset = $this->getDI()->get('config')->alipay->inputcharset;
        $signType = $this->getDI()->get('config')->alipay->signtype;
        $sellerId = $this->getDI()->get('config')->alipay->sellerid; //支付宝账号
        $notifyUlr = $this->getDI()->get('config')->alipay->notifyulr; //回调地址

        $ali = [
            'service' => 'mobile.securitypay.pay',
            'partner' => $partner,
            '_input_charset' => $inputCharset,
            'sign_type' => $signType,
            'sign' => '',
            'notify_url' => urlencode($notifyUlr), //回调地址
            'out_trade_no' => $out_trade_no, //商户网站唯一订单号
            'subject' => $subject, //商品名称
            'payment_type' => 1, //支付类型
            'seller_id' => $sellerId,
            'total_fee' => $total_fee, //总金额
            'body' => $body, //商品详情
            'count' => 1,
            'goods_id' => $goodsId,
            //'name' => 'luoji',
            //'phone' => 18971308508
        ];
        $ali = AlipayCore::argSort($ali);

        $str = '';

        foreach ($ali as $key => $val) {
            if (!in_array($key, ['sign_type', 'sign'])) {
                $val = '"' . $val . '"';
                $str .= (('' == $str) ? '' : '&') . "{$key}={$val}";
            }
        }
        $sign = mb_convert_encoding(urlencode($this->sign($str)), 'UTF8');
        $str .= '&sign=' . '"' . $sign . '"' . '&sign_type=' . '"' . $ali['sign_type'] . '"';//传给支付宝接口的数据
        //        echo $str; exit;
        return $str;
    }


    public static function getUnionpayConfig()
    {
        $certPath = dirname(dirname(dirname(__DIR__))) . '/lib/deyi/Unionpay';

        return [
            //'sign_cert_path' => $certPath . '/cert/dy.pfx', //老私钥
            'sign_cert_path' => $certPath . '/cert/dy_new.pfx', //新私钥
            'sign_cert_pwd' => 'dylife',
            'merid' => '898420148160170',
            'verify_cert_path' => $certPath . '/cert/UPOP_VERIFY.cer',
            'encript_cert_path' => $certPath . '/cert/RSA2048_PROD_index_22.cer',
            'verify_cert_dir' => $certPath . '/cert',
            'front_trans_url' => 'https://gateway.95516.com/gateway/api/frontTransReq.do',
            'back_trans_url' => 'https://gateway.95516.com/gateway/api/backTransReq.do',
            'batch_trans_url' => 'https://gateway.95516.com/gateway/api/batchTrans.do',
            'single_query_url' => 'https://gateway.95516.com/gateway/api/queryTrans.do',
            'file_query_url' => 'https://filedownload.95516.com/',
            'card_request_url' => 'https://gateway.95516.com/gateway/api/cardTransReq.do',
            'app_requert_url' => 'https://gateway.95516.com/gateway/api/appTransReq.do',
        ];
    }

    /********************************************银联支付start********************************************************/
    //订单号，总价，商品名称
    protected function unionpay($outTradeNo, $totalFee, $subject, $notifyUrl = 'http://newapi.deyi.com')
    {
        //$api_url = 'http://124.238.248.13:8081';

        //        $api_url  人工传递
        $params = [
            'version' => '5.0.0',                        //版本号
            'encoding' => 'UTF-8',                        //编码方式
            'certId' => $this->getCertId(self::getUnionpayConfig()['sign_cert_path']),                //证书ID
            'txnType' => '01',                                //交易类型
            'txnSubType' => '01',                            //交易子类
            'bizType' => '000201',                            //业务类型
            'frontUrl' => $notifyUrl,                //前台通知地址
            'backUrl' => $notifyUrl . '/coin/callback/unotify',                //后台通知地址
            'signMethod' => '01',        //签名方法
            'channelType' => '08',                    //渠道类型
            'accessType' => '0',                            //接入类型
            'merId' => self::getUnionpayConfig()['merid'],                    //商户代码
            'orderId' => $outTradeNo,                    //商户订单号
            'txnTime' => date('YmdHis'),                //订单发送时间
            'txnAmt' => $totalFee * 100,                                //交易金额
            'currencyCode' => '156',                        //交易币种
            'defaultPayType' => '0001',                        //默认支付方式
            'reqReserved' => $subject,                        //自带的JSON
        ];
        $this->union_sign($params);
        $front_uri = self::getUnionpayConfig()['app_requert_url'];
        $string = $this->sendHttpRequest($params, $front_uri);
        $result = $this->coverStringToArray($string);
        $tn = $result['tn'];

        //        echo JsonConverter::toJson(['tn' => $tn]);
        return $tn;
    }

    private function coverStringToArray($str)
    {
        $result = [];

        if (!empty($str)) {
            $temp = preg_split('/&/', $str);
            if (!empty($temp)) {
                foreach ($temp as $key => $val) {
                    $arr = preg_split('/=/', $val, 2);
                    if (!empty($arr)) {
                        $k = $arr ['0'];
                        $v = $arr ['1'];
                        $result [$k] = $v;
                    }
                }
            }
        }

        return $result;
    }

    private function getCertId($cert_path)
    {
        $sign_cert_pwd = self::getUnionpayConfig()['sign_cert_pwd'];
        $pkcs12certdata = file_get_contents($cert_path);

        openssl_pkcs12_read($pkcs12certdata, $certs, $sign_cert_pwd);
        $x509data = $certs ['cert'];
        openssl_x509_read($x509data);
        $certdata = openssl_x509_parse($x509data);
        $cert_id = $certdata ['serialNumber'];

        return $cert_id;
    }

    private function union_sign(&$params)
    {
        $sign_cert_path = self::getUnionpayConfig()['sign_cert_path'];
        if (isset($params['transTempUrl'])) {
            unset($params['transTempUrl']);
        }
        // 转换成key=val&串
        $params_str = $this->coverParamsToString($params);
        $params_sha1x16 = sha1($params_str, false);
        // 签名证书路径
        $private_key = $this->getPrivateKey($sign_cert_path);
        // 签名
        $sign_falg = openssl_sign($params_sha1x16, $signature, $private_key, OPENSSL_ALGO_SHA1);
        if ($sign_falg) {
            $signature_base64 = base64_encode($signature);
            $params ['signature'] = $signature_base64;
        } else {
            echo 'sign error';
            $this->errorLog('签名失败');
            $this->errorLog('签名串' . $params_str);
        }
    }

    private function getPrivateKey($cert_path)
    {
        $sign_cert_pwd = self::getUnionpayConfig()['sign_cert_pwd'];
        $pkcs12 = file_get_contents($cert_path);
        openssl_pkcs12_read($pkcs12, $certs, $sign_cert_pwd);

        return $certs ['pkey'];
    }

    private function coverParamsToString($params)
    {
        $sign_str = '';
        // 排序
        ksort($params);
        foreach ($params as $key => $val) {
            if ($key == 'signature') {
                continue;
            }
            $sign_str .= sprintf('%s=%s&', $key, $val);
            // $sign_str .= $key . '=' . $val . '&';
        }

        return substr($sign_str, 0, strlen($sign_str) - 1);
    }

    private function errorLog($msg)
    {
        error_log(__CLASS__ . ': ' . $msg);
    }


    /**
     * 后台交易 HttpClient通信
     *
     * @param unknown_type $params
     * @param unknown_type $url
     *
     * @return mixed
     */
    private function sendHttpRequest($params, $url)
    {
        $opts = $this->getRequestParamString($params);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);//不验证证书
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);//不验证HOST
        curl_setopt(
            $ch,
            CURLOPT_HTTPHEADER,
            [
                'Content-type:application/x-www-form-urlencoded;charset=UTF-8',
            ]
        );
        curl_setopt($ch, CURLOPT_POSTFIELDS, $opts);

        /*
         * 设置cURL 参数，要求结果保存到字符串中还是输出到屏幕上。
         */
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        // 运行cURL，请求网页
        $html = curl_exec($ch);
        // close cURL resource, and free up system resources
        curl_close($ch);

        return $html;
    }

    /**
     * 组装报文.
     *
     * @param unknown_type $params
     *
     * @return string
     */
    private function getRequestParamString($params)
    {
        $params_str = '';
        foreach ($params as $key => $value) {
            $params_str .= ($key . '=' . (!isset($value) ? '' : urlencode($value)) . '&');
        }

        return substr($params_str, 0, strlen($params_str) - 1);
    }

    //RSA签名
    public function sign($data)
    {
        //读取私钥文件
        $priKey = file_get_contents(dirname($_SERVER['DOCUMENT_ROOT']) . '/lib/deyi/Alipay/key/rsa_private_key.pem');//私钥文件路径
        $res = openssl_get_privatekey($priKey); //转换为openssl密钥，必须是没有经过pkcs8转换的私钥
        openssl_sign($data, $sign, $res); //调用openssl内置签名方法，生成签名$sign
        openssl_free_key($res); //释放资源
        $sign = base64_encode($sign); //base64编码

        return $sign;

    }


}
